#------------------------------PowerCipher 1.0.0------------------------------
#------------By Neil Power, with help from Max Baker and Wyn Price------------
#----------------------------------(C) 2015-----------------------------------
#----------------------Licensed for non-commercial reuse----------------------

#NOTE: Not compatible with v0.9.8 or older, and
#therefore DOESN'T WORK with codes created with v0.9.8 or older

#For support or queries go to help page 1

#If there are any new features you would like added please email us

#Last updated at 20/01/2016 18:07
#New in this version (1.0.0):
    #Improved testing mode - thanks Wyn!
    #Keys switch places for even more security
    #Removed "-" automatically added to end of encrypted message bug
    #Removed unnecessary variables
    #Updated copyright
    #Removed unnecessary hashtags - thanks Max!
    #Fixed a load of bugs
    #Shortened code
    #Fixed bug where saved txt file doesn't show hyphens
    #General improvements
    #Added while loops for all inputs
    #Updated comments
    #Reorganised functions
    #Code hidden for security purposes
    

import random #Needed for optional random key generation
import time #Needed for spacing out output
import os #Needed to open text file
import string #Needed to create a random string for testing
version = "1.0.0"

def getMode():#Gets and returns mode
    while True:
        print("Do you want to encrypt or decrypt a message (or type help)?")
        mode = input("Type encrypt, decrypt or help: ").lower()
        if mode in "encrypt e decrypt d help h".split():#Checks if mode is valid
            return mode[0]
        if mode.lower() == "test" or mode.lower() == "t":
            test()
        elif mode.lower() == "kill" or mode.lower() == "k":
            os._exit(1)
        elif mode.lower() == "exit" or mode.lower() == "x":
            end()
        
        else:
            print("Enter either 'encrypt' or 'e' or 'decrypt' or 'd' or 'help' or 'h'.\n")

def test():#Troubleshooting for admins - ignore this bit!
    message = ""
    for times in range(15):
        testIntOrStr = random.randint(0,1)
        if testIntOrStr == 1:
            message += random.choice(string.ascii_letters)
        else:
            message += str(random.randint(0,9))
    print("The original message was: \n", message, "\n")
    key1 = random.randint(1, 9999999)
    key2 = random.randint(1, 9999999)
    key3 = getKey3(key1, key2)
    print("Key 1 is: \n",key1, "\n")
    print("Key 2 is: \n",key2, "\n")
    print("Key 3 is: \n",key3, "\n")
    emessage = translatedMessage = translateMessage("e", message, key1, key2, key3, a, b)
    print("The encrypted message is: \n",emessage, "\n")
    messageSpace = ""
    for symbol in emessage:
        if symbol == "-":
            messageSpace = messageSpace + " "
        else:
            messageSpace = messageSpace + symbol
    print("The message without spaces is: \n", messageSpace, "\n")
    dmessage = translateMessage("d", messageSpace, key1, key2, key3, a, b)
    print("The decrypted message is: \n", dmessage, "\n")
    if dmessage == message:
        print("The code is apparently working...")
    else:
        print("Something's wrong...")
    end()

def getMessage(mode):#Gets and returns message
    messageSpace = ""
    print("Enter your message:")
    message = input()

    if mode[0] == "e":
        return message

    else:
        for symbol in message:#Replaces "-" in message with " "
            if symbol == "-":
                messageSpace = messageSpace + " "

            else:
                messageSpace = messageSpace + symbol
        return messageSpace

def getKey1(mode):#Gets and returns key1
    while True:
        if mode[0] == "e":
            key1 = input("""Enter the first key number,
type 'r' to get a random one or type 't' to use the text file: """)
            
        if mode[0] == "d":
            key1 = input("Enter the first key number or type 't' to use the text file: ")
            
        if str(key1) == "t":
            keyTxtList = open("Key1.txt","r")#Opens key1 from txt file
            keyTxt = list(keyTxtList.read())#Converts text file into list
            keyList = ""
            for symbol in keyTxt:#Turns list into string
                keyList = keyList + symbol
            return int(keyList)
        
        if str(key1) == "r" and mode[0] == "e":
            randKey1 = random.randint(0, 99999999999999999)#Randomly generates key
            print("Your first key is", randKey1)
            return int(randKey1)
        
        if key1.isalpha():
            print("Invalid Key.\n")
                
        elif (int(key1) >= 0):#Checks key1
            return int(key1)
                
        else:
            print("Invalid Key.\n")


def getKey2(mode):#Gets and returns key2
    while True:
        if mode[0] == "e":
            key2 = input("""Enter the second key number,
type 'r' to get a random one or type 't' to use the text file: """)
            
        if mode[0] == "d":
            key2 = input("Enter the second key number or type 't' to use the text file: ")
            
        if str(key2) == "t":
            keyTxtList = open("Key2.txt","r")#Opens key2 from txt file
            keyTxt = list(keyTxtList.read())#Converts text file into list
            keyList = ""
            for symbol in keyTxt:#Turns list into string
                keyList = keyList + symbol
            return int(keyList)
        
        if str(key2) == "r" and mode[0] == "e":
            randKey2 = random.randint(0, 99999999999999999)#Randomly generates key
            print("Your second key is", randKey2)
            return int(randKey2)
        
        if key2.isalpha():
            print("Invalid Key.\n")
                
        elif (int(key2) >= 0):#Checks key2
            return int(key2)
                
        else:
            print("Invalid Key.\n")
            


def getKey3(key1, key2):#Generates a third key based on the other two
    key3 = (key1 + key2)/2
    return int(round(key3, 0))#Returns key3 as int to round to 0dp


def translateMessage(mode, message, key1, key2, key3, a, b):#Translates message into encrypted or decrypted form
    translated = ""
    staticKey1 = key1#Creates a version of key1 that doesn't change
    staticKey2 = key2#Creates a version of key2 that doesn't change
    staticKey3 = key3#Creates a version of key3 that doesn't change
    
    if mode[0] == "e":#Encrypts message

        for symbol in message:#Runs through each symbol in message
            key1 += staticKey2#Increases key1 by key2
            key2 += staticKey3#Increases key2 by key3
            key3 += staticKey1#Increases key3 by key1
            key1, key2 = key2, key1#Swaps keys
            key2, key3 = key3, key2#Swaps keys
            num = ord(symbol)#Converts symbol in message to ASCII number
            num = eval(a)#Encryption code hidden for security purposes
            translated = translated + str(num) + "-"#Adds encrypted to message and "-" between each symbol
        translated = translated[0:(int(len(translated))-1)]
    if mode[0] == "d":#Decrypts message
        messageList = message.split()#Splits message into the blocks of numbers that are the symbols

        for symbol in messageList:#Runs through each symbol in message
            key1 += staticKey2#Increases key1 by key2
            key2 += staticKey3#Increases key2 by key3
            key3 += staticKey1#Increases key3 by key1
            key1, key2 = key2, key1#Swaps keys
            key2, key3 = key3, key2#Swaps keys
            num = eval(b)#Decryption code hidden for security purposes
            translated = translated + chr(num)#Adds decrypted to message

    return translated

def helpScreen():#Runs help commands
    def programHelp():#Print help on how to use program
        print()
        print("""--------------------------------PROGRAM HELP:--------------------------------\n
    To use this program, first select your mode.
        Encrypt: Encrypts a text message using two keys
        Decrypt: Decrypts a text message if you know the two keys
        Help: Opens the help menu\n""")
        time.sleep(7)
        print("""Then, enter your message. This can be anything you like,
    as long as it doesn't contain blank lines.\n""")
        time.sleep(5)
        print("""You are then prompted to enter the first key.
        If you are in encrypt mode, you also have the option
        to randomly generate the second key. Just type 'r'.
        Remember this key, as you'll need it to decrypt the message.""")
        time.sleep(8)
        print("""You are then prompted to enter the second key.
        If you are in encrypt mode, you also have the option
        to randomly generate the second key. Just type 'r'.
        Remember this key, as you'll need it to decrypt the message.\n""")
        time.sleep(8)
        print("Your encrypted/decrypted message is then displayed.\n")
        time.sleep(4)
        print("""You then have the option to save the result to a text file.
    If you type yes, then the result will be saved in the same folder as the program is in.\n""")
        time.sleep(6)
        print("If you want to run the program again, type 'y'.")
        time.sleep(2)
        print("Simple!\n")
        time.sleep(2)
        print("""For any other issues, please email np16@outlook.com,
    wynprice999@gmail.com or maxb125@hotmail.com \n""")
        time.sleep(5)

    def howItWorks():#Prints help on how program works
        print()
        print("""--------------------------------HOW IT WORKS:--------------------------------\n
    PowerCipher works using some complicated maths,
    but crucially using the chr() and ord() functions.
    These allow the message to be converted into the ASCII key,
    which is a series of numbers used to represent symbols.
    These numbers are then encrypted by the two keys using the following method:""")
        time.sleep(1)
        print("""
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        [Blocked for security reasons]
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n""")
        time.sleep(1)
        input()
        print("""and then printed.
    Decrypting does the exact opposite.\n
    Simple!\n""")


    def programLicense():#Prints license for program
        print()
        print("""A. HISTORY OF THE SOFTWARE
    ==========================
    PowerCipher, formerly NeilCipher, was created in 2015 by Neil Power,
    although it also includes contributions from
    Max Baker and Wyn Price. There have been a number of releases, and the
    latest one is currently""", version, """ \n
    Press enter to continue: """)
        input()
        print("""
    B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING POWERCIPHER
    ====================================================================\n
    POWERCIPHER LICENSE
    -------------------\n
    1. This LICENSE AGREEMENT is between the authors of PowerCipher
    ("The Authors"), and the Individual or Organization ("THE USER") accessing and
    otherwise using this software ("PowerCipher")\n
    2. Subject to the terms and conditions of this License Agreement, THE AUTHORS hereby
    grants THE USER a nonexclusive, royalty-free, world-wide license to reproduce,
    analyse, test, perform and/or display publicly, prepare derivative works,
    distribute, and otherwise use PowerCipher alone or in any derivative version,
    provided, however, that THE AUTHORS's names are retained and quoted.\n
    Press enter to continue: """)
        input()
        print("""   3. In the event THE USER prepares a derivative work that is based on
    or incorporates PowerCipher or any part thereof, and wants to make
    the derivative work available to others as provided herein, then
    THE USER hereby agrees to include in any such work a brief summary of
    the changes made to PowerCipher.\n
    4. THE AUTHORS are making PowerCipher available to THE USER on an "AS IS"
    basis.  THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
    IMPLIED.  THE AUTHORS MAKE NO AND DISCLAIMS ANY REPRESENTATION 
    OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE
    OR THAT THE USE OF POWERCIPHER WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.\n
    5. THE AUTHORS SHALL NOT BE LIABLE TO USER OR ANY OTHER USERS OF POWERCIPHER
    FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
    A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING POWERCIPHER,
    OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.\n
    Press enter to continue: """)
        input()
        print("""   6. This License Agreement will automatically terminate upon a material
    breach of its terms and conditions.\n
    7. Nothing in this License Agreement shall be deemed to create any
    relationship of agency, partnership, or joint venture between THE AUTHORS and
    THE USER.  This License Agreement does not grant permission to use THE AUTHORS
    trademarks or trade name in a trademark sense to endorse or promote
    products or services of THE USER, or any third party.\n
    8. By copying, installing or otherwise using PowerCipher, THE USER
    agrees to be bound by the terms and conditions of this License
    Agreement.\n
    9. Any co-authors of this code agree to let Neil Power have 100%
    of any profits that may be received by this program
    Press enter to continue: """)
        input()
        print("""   IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
    FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
    DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.\n
    THE AUTHORS BEAR NO LIABILITY WHATSOEVERFOR ANY DIRECT, INDIRECT,
    SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES AS A RESULT OF
    MESSAGES BEING DECRYPTED BY A THIRD PARTY. THE AUTHORS DO NOT
    GUARANTEE THAT MESSAGES ENCRYPTED USING THIS SOFTWARE WILL
    BE SECURE.THIS PROGRAM IS DESIGNED FOR INFORMAL USE ONLY,
    AND SHOULD NOT BE USED TO ENCRYPT CONFIDENTIAL INFORMATION.\n
    THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE 
    MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
    MODIFICATIONS. ANY NON-OFFICIAL [NOT AUTHORISED BY NEIL POWER]
    RELEASES THAT CLAIM TO BE THE OFFICIAL VERSION WILL BE DESTROYED\n""")
        print("Press enter to return to menu: ")
        input()


    def programCredits():#Prints credits
        print()
        print("-----------------------------------CREDITS-----------------------------------\n")
        print("This program was written by:\n")
        time.sleep(1)
        print("NEIL POWER\n")
        time.sleep(1)
        print("With assistance and testing provided by:\n")
        time.sleep(1)
        print("MAX BAKER\n")
        time.sleep(1)
        print("and\n")
        time.sleep(1)
        print("WYN PRICE\n")

    def programCopyright():#Prints Copyright
        print()
        print("----------------------------------COPYRIGHT----------------------------------\n")
        print("""This program was made by Neil Power, with help from Max Baker and Wyn Price,
    and is licensed for non-commercial (or personal) reuse with or without modification.
    I request that you retain the author's name if modifying this program.
    Permission to publish online, or use commercially can be obtained
    from Neil Power (np16@outlook.com)               
    Thank you for your cooperation with these requests,
    and I hope that you enjoyed using this program.
    Please contact any of the following emails for support or questions:\n
    Neil Power (np16@outlook.com) \n
    or \n
    Wyn Price(wynprice999@gmail.com) \n
    or \n
    Max Baker(maxb125@hotmail.co.uk) \n""")
    helpChoice = ""
    print()
    print("Welcome to help for PowerCipher", version, "\n")
    while helpChoice not in "1 2 3 4 5 6 7 cancel c".split():
        print("""1) Get help on using this program
2) See how this program works
3) View the Python software license
4) View the PowerCipher software license
5) View the credits for this program
6) View the credits for Python
7) View the copyright for this program
8) View the copyright for Python
Or type cancel to return to the main menu.""")

        helpChoice = input("Please enter the number for your choice (or cancel): ")

        if helpChoice == "1":
            programHelp()
            time.sleep(2)
        if helpChoice == "2":
            howItWorks()
            time.sleep(2)
        if helpChoice == "3":
            print()
            license()
            time.sleep(2)
        if helpChoice == "4":
            programLicense()
        if helpChoice == "5":
            programCredits()
            time.sleep(2)
        if helpChoice == "6":
            credits()
            time.sleep(2)
        if helpChoice == "7":
            programCopyright()
            time.sleep(2)
        if helpChoice == "8":
            copyright()
            time.sleep(2)

a = "int((((((num*key1)+key2)-key3)-key1)+key2)-key3)"
def saveResult(resultChoice, message, key1, key2, translatedMessage, mode):#Option to write result to txt file
    if resultChoice[0] == "y":
        saveChoice = " "
        messageSpace = ""
        while str(saveChoice[0]) != "1" and str(saveChoice[0]) != "2":
            saveChoice = input("""Type 1 to save the full result,
or 2 to just save the translated message: """)
            if mode[0] == "e":
                for symbol in translatedMessage:#Replaces " " in message with "-"
                    if symbol == " ":
                        messageSpace = messageSpace + "-"
                    else:
                        messageSpace = messageSpace + symbol
                translatedMessage = messageSpace
            if saveChoice[0] == "1":
                with open('TranslatedMessage.txt', 'w') as file:#Creates a txt file and writes result in it
                    file.write("""-------------------------------PowerCipher """+version+"""------------------------------
------------By Neil Power, with help from Max Baker and Wyn Price------------
----------------------------------(C) 2015----------------------------------- \n""")
                    file.write(message)
                    file.write("\n with keys "+str(key1)+" and "+str(key2)+" is \n")
                    file.write(translatedMessage)
            if saveChoice[0] == "2":
                with open('TranslatedMessage.txt', 'w') as file:#Creates a txt file and writes result in it
                    file.write("-------------------------------PowerCipher ")
                    file.write(version)
                    file.write("------------------------------ \n")
                    file.write("------------By Neil Power, with help from Max Baker and Wyn Price------------ \n")
                    file.write("----------------------------------(C) 2015----------------------------------- \n")
                    file.write(translatedMessage)

        print("The result has been saved in TranslatedMessage.txt")
        openChoice = ""
        while openChoice != "y" and openChoice != "n":
            openChoice = input("Would you like to open it? (y/n)")
            if openChoice == "y":
                os.startfile("TranslatedMessage.txt")
            else:
                openChoice = input("Would you like to open it? (y/n)")    
b = "int((((((int(symbol)+key3)-key2)+key1)+key3)-key2)/key1)"

def end():
    endChoice = ""
    while endChoice != "y" and endChoice != "n":
        endChoice = input("Would you like to end this program? (y/n)")
        if endChoice[0] == "y":
            print("Ok!")
            exit()
        else:
            print("Ok!")


def main():
    mode = getMode()#Gets mode
    if mode[0] == "h":#Prints help screen
        helpScreen()
    else:
        message = getMessage(mode)#Gets message, and if decrypting replaces "-" in message with " "
        key1 = getKey1(mode)#Gets key1
        key2 = getKey2(mode)#Gets key2
        key3 = getKey3(key1, key2)#Gets key3
        print("Your translated text is: \n")
        translatedMessage = translateMessage(mode, message, key1, key2, key3, a, b)
        print(translatedMessage)#Prints final message
        resultChoice = input("Would you like to save the message in a text file? (y/n)")
        saveResult(resultChoice, message, key1, key2, translatedMessage, mode)
        end()



print("------------------------------PowerCipher", version +"------------------------------")
print("------------By Neil Power, with help from Max Baker and Wyn Price------------")
print("----------------------------------(C) 2015----------------------------------- \n")

while True:
    main()#Runs forever......................................................
   
